/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simulator;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3f;
import org.jdom.Element;
import simulator.XMLParser.XMLParserException;

/**
 *
 * @author vdelaitr
 */

enum ObjectTypes {
    COMPOUND, BOX, CYLINDER, SPHERE
}

/******************************************************************************/
abstract class ObjectInterface {
    ObjectTypes type;

    Vector3f position;
    Vector3f rotation;

    public static class ObjectException extends Exception {
        ObjectException(String message) {
            super(message);
        }
    }    
}

/******************************************************************************/
class CompoundObject extends ObjectInterface {
    // The group of contained objects
    private List<ObjectInterface> objects;

    CompoundObject() {
        type = ObjectTypes.COMPOUND;
        objects = new LinkedList<ObjectInterface>();
    }

    // The list of object children
    public List<ObjectInterface> getObjectList() {
        return objects;
    }

    // Add an object
    public void addObject(ObjectInterface obj) {
        objects.add(obj);
    }

    static CompoundObject parse(Element root) throws ObjectException {
        CompoundObject obj = new CompoundObject();

        Iterator itr = (root.getChildren()).iterator();
        while(itr.hasNext()) {
            Element e = (Element)itr.next();
            String tag = e.getName();
            if (tag.equals("box")) {
                obj.addObject(BoxObject.parse(e));
            } else if(tag.equals("cylinder")) {
                obj.addObject(CylinderObject.parse(e));
            } else if(tag.equals("sphere")) {
                obj.addObject(SphereObject.parse(e));
            } else if(tag.equals("objects")) {
                obj.addObject(parse(e));
            } else {
                throw new ObjectException("Unknown object \"" + tag + "\"");
            }
        }
        
        return obj;
    }
}

/******************************************************************************/
abstract class PhysicalObject extends ObjectInterface {

    /*** Physical attributes ***/
    // Weight
    float weight;

    /*** Visual attributes ***/
    // Color
    Color3f color;
}

/******************************************************************************/
class BoxObject extends PhysicalObject {
    // Box dimensions
    Vector3f dimension;

    BoxObject() {
        type = ObjectTypes.BOX;
    }

    static BoxObject parse(Element root) throws ObjectException {
        Element e;
        BoxObject box = new BoxObject();

        try {
            e = root.getChild("dimension");
            if (e == null)
                throw new ObjectException("Could not find child \"dimension\" for box object.");
            else
                box.dimension = XMLParser.parseVector(e);

            e = root.getChild("position");
            if (e == null)
                throw new ObjectException("Could not find child \"position\" for box object.");
            else
                box.position = XMLParser.parseVector(e);

            e = root.getChild("rotation");
            if (e == null)
                throw new ObjectException("Could not find child \"rotation\" for box object.");
            else
                box.rotation = XMLParser.parseVector(e);

            e = root.getChild("color");
            if (e == null)
                throw new ObjectException("Could not find child \"color\" for box object.");
            else
                box.color = XMLParser.parseColor(e);
        }
        catch (XMLParserException ex) {
            throw new ObjectException(ex.getMessage());
        }

        return box;
    }
}

/******************************************************************************/
class CylinderObject extends PhysicalObject {
    // Cylinder dimensions
    float radius, length;

    CylinderObject() {
        type = ObjectTypes.CYLINDER;
    }

    static CylinderObject parse(Element root) throws ObjectException {
        Element e;
        CylinderObject cylinder = new CylinderObject();

        try {
            e = root.getChild("radius");
            if (e == null)
                throw new ObjectException("Could not find child \"radius\" for cylinder object.");
            else
                cylinder.radius = XMLParser.parseValue(e);

            e = root.getChild("length");
            if (e == null)
                throw new ObjectException("Could not find child \"length\" for cylinder object.");
            else
                cylinder.length = XMLParser.parseValue(e);

            e = root.getChild("position");
            if (e == null)
                throw new ObjectException("Could not find child \"position\" for cylinder object.");
            else
                cylinder.position = XMLParser.parseVector(e);

            e = root.getChild("rotation");
            if (e == null)
                throw new ObjectException("Could not find child \"rotation\" for cylinder object.");
            else
                cylinder.rotation = XMLParser.parseVector(e);

            e = root.getChild("color");
            if (e == null)
                throw new ObjectException("Could not find child \"color\" for cylinder object.");
            else
                cylinder.color = XMLParser.parseColor(e);
        }
        catch (XMLParserException ex) {
            throw new ObjectException(ex.getMessage());
        }

        return cylinder;
    }
}

/******************************************************************************/
class SphereObject extends PhysicalObject {
    // Sphere dimensions
    float radius;

    SphereObject() {
        type = ObjectTypes.SPHERE;
    }

    static SphereObject parse(Element root) throws ObjectException {
        Element e;
        SphereObject shpere = new SphereObject();

        try {
            e = root.getChild("radius");
            if (e == null)
                throw new ObjectException("Could not find child \"radius\" for shpere object.");
            else
                shpere.radius = XMLParser.parseValue(e);

            e = root.getChild("position");
            if (e == null)
                throw new ObjectException("Could not find child \"position\" for shpere object.");
            else
                shpere.position = XMLParser.parseVector(e);

            e = root.getChild("rotation");
            if (e == null)
                throw new ObjectException("Could not find child \"rotation\" for shpere object.");
            else
                shpere.rotation = XMLParser.parseVector(e);

            e = root.getChild("color");
            if (e == null)
                throw new ObjectException("Could not find child \"color\" for shpere object.");
            else
                shpere.color = XMLParser.parseColor(e);
        }
        catch (XMLParserException ex) {
            throw new ObjectException(ex.getMessage());
        }

        return shpere;
    }
}